package communication

import (
	"bytes"
	"context"
	"fmt"
	"math/rand"
	"os"
	"path/filepath"
	"text/template"
	"time"

	"gitee.com/wangshh_123/cross-pay-go/src/config"
	"gitee.com/wangshh_123/cross-pay-go/src/database"

	"github.com/redis/go-redis/v9"
	"gopkg.in/gomail.v2"
)

// EmailUtil 邮件工具
type EmailUtil struct {
	dialer *gomail.Dialer
	redis  *redis.Client
	tmpl   *template.Template
	from   string // 发件人地址
}

// getTemplatePath 获取模板文件路径
func getTemplatePath() (string, error) {
	// 从配置文件获取可能的路径列表
	possiblePaths := config.GlobalConfig.Email.Template.Paths

	// 如果配置文件中没有路径，使用默认路径
	if len(possiblePaths) == 0 {
		possiblePaths = []string{
			"template/email.html",                // 相对于当前目录
			"src/template/email.html",            // 相对于项目根目录
			"/www/wwwroot/backend_go/email.html", // Linux系统路径
			"D:/project/CrossBorderEComDev/cross-pay-go/src/template/email.html", // Windows开发路径
		}
	}

	// 遍历所有可能的路径
	for _, path := range possiblePaths {
		if _, err := os.Stat(path); err == nil {
			return path, nil
		}
	}

	// 如果上述路径都不存在，尝试使用当前执行文件的路径
	execPath, err := os.Executable()
	if err == nil {
		execDir := filepath.Dir(execPath)
		templatePath := filepath.Join(execDir, "template", "email.html")
		if _, err := os.Stat(templatePath); err == nil {
			return templatePath, nil
		}
	}

	return "", fmt.Errorf("template_file_not_found: 请确保email.html模板文件存在于template目录中")
}

// NewEmailUtil 创建邮件工具实例
func NewEmailUtil() (*EmailUtil, error) {
	var host, username, password, from string
	var port int

	// 根据provider选择不同的邮件配置
	switch config.GlobalConfig.Email.Provider {
	case "qq":
		host = "smtp.qq.com"
		port = 465
		username = config.GlobalConfig.Email.QQ.Username
		password = config.GlobalConfig.Email.QQ.Password
		from = config.GlobalConfig.Email.QQ.Username
	case "163":
		host = config.GlobalConfig.Email.Host
		port = config.GlobalConfig.Email.Port
		username = config.GlobalConfig.Email.Username
		password = config.GlobalConfig.Email.Password
		from = config.GlobalConfig.Email.Username
	case "outlook":
		// Outlook配置需要特殊处理，这里暂时使用通用配置
		host = "smtp-mail.outlook.com"
		port = 587
		username = config.GlobalConfig.Email.Username
		password = config.GlobalConfig.Email.Password
		from = config.GlobalConfig.Email.Username
	case "zoho":
		// Zoho使用SMTP配置
		host = config.GlobalConfig.Email.Host
		port = config.GlobalConfig.Email.Port
		username = config.GlobalConfig.Email.Username
		password = config.GlobalConfig.Email.Password
		from = config.GlobalConfig.Email.From
	default:
		// 默认使用通用配置
		host = config.GlobalConfig.Email.Host
		port = config.GlobalConfig.Email.Port
		username = config.GlobalConfig.Email.Username
		password = config.GlobalConfig.Email.Password
		from = config.GlobalConfig.Email.Username
	}

	// 创建邮件发送器（所有提供商都使用SMTP）
	dialer := gomail.NewDialer(host, port, username, password)

	// 获取模板文件路径
	templatePath, err := getTemplatePath()
	if err != nil {
		return nil, fmt.Errorf("get_template_path_failed: %v", err)
	}

	// 读取并解析模板文件
	tmpl, err := template.ParseFiles(templatePath)
	if err != nil {
		return nil, fmt.Errorf("parse_email_template_failed: %v", err)
	}

	emailUtil := &EmailUtil{
		dialer: dialer,
		redis:  database.RedisClient,
		tmpl:   tmpl,
		from:   from,
	}

	return emailUtil, nil
}

// SendLoginCode 发送登录验证码
func (e *EmailUtil) SendLoginCode(email string) error {
	return e.SendVerificationCode(email, "login")
}

// SendRegisterCode 发送注册验证码
func (e *EmailUtil) SendRegisterCode(email string) error {
	return e.SendVerificationCode(email, "register")
}

// SendResetPasswordCode 发送重置密码验证码
func (e *EmailUtil) SendResetPasswordCode(email string) error {
	return e.SendVerificationCode(email, "reset_password")
}

// SendForgotPasswordCode 发送忘记密码验证码
func (e *EmailUtil) SendForgotPasswordCode(email string) error {
	return e.SendVerificationCode(email, "forgot_password")
}

// SendVerificationCode 发送验证码邮件
func (e *EmailUtil) SendVerificationCode(email, purpose string) error {
	ctx := context.Background()

	// 生成6位随机验证码
	code := fmt.Sprintf("%06d", rand.Intn(1000000))

	// 存储验证码到Redis，设置5分钟过期
	key := fmt.Sprintf("email:verification:%s:%s", purpose, email)
	err := e.redis.Set(ctx, key, code, 5*time.Minute).Err()
	if err != nil {
		return fmt.Errorf("store_verification_code_failed: %v", err)
	}

	// 准备模板数据
	var titleEn, titleZh, titleVi string
	var greetingEn, greetingZh, greetingVi string
	var warningEn, warningZh, warningVi string

	switch purpose {
	case "login":
		titleEn = "Login Verification Code"
		titleZh = "登录验证码"
		titleVi = "Mã Xác Minh Đăng Nhập"

		greetingEn = "Hello, you are logging in"
		greetingZh = "您好，您正在进行登录操作"
		greetingVi = "Xin chào, bạn đang đăng nhập"

		warningEn = "If this is not your operation, please contact customer service immediately. For your account security, please do not share the verification code with others."
		warningZh = "如非本人操作，请立即联系客服。为了您的账户安全，请勿将验证码告知他人。"
		warningVi = "Nếu đây không phải là hoạt động của bạn, vui lòng liên hệ với dịch vụ khách hàng ngay lập tức. Vì sự an toàn tài khoản của bạn, vui lòng không chia sẻ mã xác minh với người khác."

	case "register":
		titleEn = "Registration Verification Code"
		titleZh = "注册验证码"
		titleVi = "Mã Xác Minh Đăng Ký"

		greetingEn = "Welcome to GoPay Cross-Border Payment"
		greetingZh = "欢迎注册GoPay跨境支付"
		greetingVi = "Chào mừng đến với GoPay Thanh Toán Xuyên Biên Giới"

		warningEn = "Please do not share the verification code with others to protect your account security."
		warningZh = "请勿将验证码告知他人，以保护您的账户安全。"
		warningVi = "Vui lòng không chia sẻ mã xác minh với người khác để bảo vệ an toàn tài khoản của bạn."

	case "reset_password":
		titleEn = "Password Reset Verification Code"
		titleZh = "重置密码验证码"
		titleVi = "Mã Xác Minh Đặt Lại Mật Khẩu"

		greetingEn = "You are resetting your password"
		greetingZh = "您正在进行密码重置操作"
		greetingVi = "Bạn đang đặt lại mật khẩu"

		warningEn = "If this is not your operation, please contact customer service immediately. For your account security, please do not share the verification code with others."
		warningZh = "如非本人操作，请立即联系客服。为了您的账户安全，请勿将验证码告知他人。"
		warningVi = "Nếu đây không phải là hoạt động của bạn, vui lòng liên hệ với dịch vụ khách hàng ngay lập tức. Vì sự an toàn tài khoản của bạn, vui lòng không chia sẻ mã xác minh với người khác."

	case "forgot_password":
		titleEn = "Forgot Password Verification Code"
		titleZh = "忘记密码验证码"
		titleVi = "Mã Xác Minh Quên Mật Khẩu"

		greetingEn = "You are resetting your password"
		greetingZh = "您正在进行密码重置操作"
		greetingVi = "Bạn đang đặt lại mật khẩu"

		warningEn = "If this is not your operation, please contact customer service immediately. For your account security, please do not share the verification code with others."
		warningZh = "如非本人操作，请立即联系客服。为了您的账户安全，请勿将验证码告知他人。"
		warningVi = "Nếu đây không phải là hoạt động của bạn, vui lòng liên hệ với dịch vụ khách hàng ngay lập tức. Vì sự an toàn tài khoản của bạn, vui lòng không chia sẻ mã xác minh với người khác."

	default:
		titleEn = "Verification Code"
		titleZh = "验证码"
		titleVi = "Mã Xác Minh"

		greetingEn = "Hello"
		greetingZh = "您好"
		greetingVi = "Xin chào"

		warningEn = "Please do not share the verification code with others."
		warningZh = "请勿将验证码告知他人。"
		warningVi = "Vui lòng không chia sẻ mã xác minh với người khác."
	}

	data := struct {
		TitleEn    string
		TitleZh    string
		TitleVi    string
		GreetingEn string
		GreetingZh string
		GreetingVi string
		Code       string
		Expiration string
		WarningEn  string
		WarningZh  string
		WarningVi  string
		Year       int
	}{
		TitleEn:    titleEn,
		TitleZh:    titleZh,
		TitleVi:    titleVi,
		GreetingEn: greetingEn,
		GreetingZh: greetingZh,
		GreetingVi: greetingVi,
		Code:       code,
		Expiration: "5 minutes",
		WarningEn:  warningEn,
		WarningZh:  warningZh,
		WarningVi:  warningVi,
		Year:       time.Now().Year(),
	}

	// 渲染模板
	var body bytes.Buffer
	if err := e.tmpl.Execute(&body, data); err != nil {
		return fmt.Errorf("render_email_template_failed: %v", err)
	}

	// 使用SMTP发送邮件（包括Zoho）
	m := gomail.NewMessage()
	m.SetHeader("From", e.from)
	m.SetHeader("To", email)
	m.SetHeader("Subject", titleEn) // 使用英文标题作为邮件主题
	m.SetBody("text/html", body.String())

	if err := e.dialer.DialAndSend(m); err != nil {
		// 发送失败时删除Redis中的验证码
		e.redis.Del(ctx, key)
		return fmt.Errorf("send_email_failed: %v", err)
	}

	return nil
}

// VerifyLoginCode 验证登录验证码
func (e *EmailUtil) VerifyLoginCode(email, code string) (bool, error) {
	return e.VerifyCode(email, code, "login")
}

// VerifyRegisterCode 验证注册验证码
func (e *EmailUtil) VerifyRegisterCode(email, code string) (bool, error) {
	return e.VerifyCode(email, code, "register")
}

// VerifyResetPasswordCode 验证重置密码验证码
func (e *EmailUtil) VerifyResetPasswordCode(email, code string) (bool, error) {
	return e.VerifyCode(email, code, "reset_password")
}

// VerifyCode 验证邮件验证码
func (e *EmailUtil) VerifyCode(email, code, purpose string) (bool, error) {
	ctx := context.Background()
	key := fmt.Sprintf("email:verification:%s:%s", purpose, email)

	// 从Redis获取验证码
	savedCode, err := e.redis.Get(ctx, key).Result()
	if err == redis.Nil {
		return false, fmt.Errorf("verification_code_expired")
	} else if err != nil {
		return false, fmt.Errorf("get_verification_code_failed: %v", err)
	}

	// 验证码比对
	if savedCode != code {
		return false, fmt.Errorf("invalid_verification_code")
	}

	// 验证成功后删除验证码
	err = e.redis.Del(ctx, key).Err()
	if err != nil {
		return false, fmt.Errorf("delete_verification_code_failed: %v", err)
	}

	return true, nil
}

// SendUnusualLoginAlert 发送异常登录提醒
func (e *EmailUtil) SendUnusualLoginAlert(email string, loginInfo struct {
	IP       string
	Location string
	Time     time.Time
	Device   string
}) error {
	// 准备模板数据 - 使用与验证码邮件相同的数据结构
	data := struct {
		TitleEn    string
		TitleZh    string
		TitleVi    string
		GreetingEn string
		GreetingZh string
		GreetingVi string
		Code       string
		Expiration string
		WarningEn  string
		WarningZh  string
		WarningVi  string
		Year       int
	}{
		TitleEn:    "Unusual Login Alert",
		TitleZh:    "异常登录提醒",
		TitleVi:    "Cảnh Báo Đăng Nhập Bất Thường",
		GreetingEn: "Your account has been accessed from an unusual location",
		GreetingZh: "检测到您的账户发生了异常登录",
		GreetingVi: "Phát hiện tài khoản của bạn đã đăng nhập bất thường",
		Code: fmt.Sprintf("IP: %s\nLocation: %s\nTime: %s\nDevice: %s",
			loginInfo.IP,
			loginInfo.Location,
			loginInfo.Time.Format("2006-01-02 15:04:05"),
			loginInfo.Device),
		Expiration: "immediate",
		WarningEn:  "If this is not your operation, please change your password immediately and contact customer service.",
		WarningZh:  "如果这不是您的操作，请立即修改密码并联系客服。",
		WarningVi:  "Nếu đây không phải là hoạt động của bạn, vui lòng thay đổi mật khẩu ngay lập tức và liên hệ với dịch vụ khách hàng.",
		Year:       time.Now().Year(),
	}

	// 渲染模板
	var body bytes.Buffer
	if err := e.tmpl.Execute(&body, data); err != nil {
		return fmt.Errorf("render_email_template_failed: %v", err)
	}

	// 使用SMTP发送邮件（包括Zoho）
	m := gomail.NewMessage()
	m.SetHeader("From", e.from)
	m.SetHeader("To", email)
	m.SetHeader("Subject", "异常登录提醒")
	m.SetBody("text/html", body.String())

	if err := e.dialer.DialAndSend(m); err != nil {
		return fmt.Errorf("send_email_failed: %v", err)
	}

	return nil
}

// sendEmail 发送邮件
func (e *EmailUtil) sendEmail(to, subject, content string) error {
	// 准备模板数据
	data := struct {
		Title       string
		Greeting    string
		Description string
		Content     string
		Warning     string
		Year        int
	}{
		Title:       subject,
		Greeting:    "您好",
		Description: content,
		Warning:     "如果这不是您的操作，请忽略此邮件。",
		Year:        time.Now().Year(),
	}

	// 渲染模板
	var body bytes.Buffer
	if err := e.tmpl.Execute(&body, data); err != nil {
		return fmt.Errorf("render_email_template_failed: %v", err)
	}

	// 使用SMTP发送邮件（包括Zoho）
	m := gomail.NewMessage()
	m.SetHeader("From", e.from)
	m.SetHeader("To", to)
	m.SetHeader("Subject", subject)
	m.SetBody("text/html", body.String())

	return e.dialer.DialAndSend(m)
}
